package org.review.algorithm.stack;

public class Calculator {

    public static void main(String[] args) {
      /*  String expression = "7*2*2-5+1-5+3-4";
        generalOperations(expression);
*/
        //TODO 完成课后练习 处理小括号
        String expression = "7*2*2-5+1-(5+3)-4";

        ArrayStack numStack = new ArrayStack(10);
        ArrayStack operaStack = new ArrayStack(10);
        int index = 0;
        String temp = "";


        while (index != expression.length()) {
            char ch = expression.substring(index, index + 1).charAt(0);

            if (operaStack.isOpera(ch)) {
                if (!operaStack.isEmpty()) {
                    //TODO 如果是) 就一直弹栈 直到遇到（

                    if (ch == ')') {
                        while (operaStack.peek() != '(') {
                            int num1 = numStack.pop();
                            int num2 = numStack.pop();
                            int opera = operaStack.pop();
                            numStack.push(operaStack.calc(num1, num2, opera));
                        }
                        operaStack.pop();
                    } else if (ch == '(') {
                        operaStack.push(ch);
                    } else if (operaStack.priority(operaStack.peek()) >= operaStack.priority(ch)) {
                        int num1 = numStack.pop();
                        int num2 = numStack.pop();
                        int opera = operaStack.pop();
                        numStack.push(operaStack.calc(num1, num2, opera));
                        operaStack.push((char) ch);
                    } else {
                        operaStack.push(ch);
                    }
                } else {
                    operaStack.push((char) ch);
                }
            } else {//TODO 处理数值
                numStack.push(ch - 48);
            }

            index++;
        }


        while (!operaStack.isEmpty()) {
            int num1 = numStack.pop();
            int num2 = numStack.pop();
            int operator = operaStack.pop();
            numStack.push(operaStack.calc(num1, num2, operator));
        }
        System.out.println(numStack.pop());


    }

    /**
     * 普通运算 不带括号的加减成除
     *
     * @param expression
     */
    private static void generalOperations(String expression) {
        ArrayStack numStack = new ArrayStack(10);
        ArrayStack operStack = new ArrayStack(10);
        int index = 0;
        String temp = "";
        while (index != expression.length()) {
            char ch = expression.charAt(index++); //todo 老师这里用的是subString.charAt(0) 实际逻辑是一样的，注意判断结束的方式即可
            if (operStack.isOpera(ch)) {
                //todo 如果是操作符 判断是否小于队列里的，如果是就pop出num栈的两个值和操作符栈 进行运算
                if (!operStack.isEmpty()) {
                    if (operStack.priority(operStack.peek()) >= operStack.priority(ch)) {
                        int num1 = numStack.pop();
                        int num2 = numStack.pop();
                        int operator = operStack.pop();
                        numStack.push(operStack.calc(num1, num2, operator));
                        operStack.push(ch);
                    } else {
                        operStack.push(ch);
                    }
                } else {
                    operStack.push(ch);
                }

            } else {//todo 处理当数字是多位的时候
                temp = temp + ch;
                if (index == expression.length()) {
                    numStack.push(Integer.parseInt(temp));
                } else if (operStack.isOpera(expression.charAt(index))) {
                    numStack.push(Integer.parseInt(temp));
                    temp = "";
                }
            }
        }

        while (!operStack.isEmpty()) {
            int num1 = numStack.pop();
            int num2 = numStack.pop();
            int operator = operStack.pop();
            numStack.push(operStack.calc(num1, num2, operator));
        }
        System.out.println(numStack.pop());
    }
}

class ArrayStack {
    int[] stack;
    int top = -1;
    int maxSize;


    public ArrayStack(int maxSize) {
        if (maxSize <= 0) throw new RuntimeException("栈不能为空");
        this.maxSize = maxSize;
        stack = new int[maxSize];
    }

    public int peek() {
        return stack[top];
    }

    public int priority(int c) {
        //TODO 需要处理小括号的优先级
        int priority = -1; //TODO 不是操作符号就返回-1

        if (c == '*' || c == '/') {
            priority = 1;
        } else if (c == '+' || c == '-') {
            priority = 0;
        }
        return priority;
    }

    public boolean isOpera(char c) {
        return c == '*' || c == '/' || c == '-' || c == '+' || c == '(' || c == ')';
    }

    public int calc(int num1, int num2, int oper) {
        int res = 0;
        switch (oper) {
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1;
                break;
            case '*':
                res = num1 * num2; //todo 这里是因为 numStack.pop的时候 顺序是反的
                break;
            case '/':
                res = num2 / num1;
                break;
        }

        return res;
    }

    public void push(int num) {
        if (isFull()) throw new RuntimeException("栈已满");
        stack[++top] = num;
    }

    public int pop() {
        if (isEmpty()) throw new RuntimeException("栈为空");
        return stack[top--];
    }

    public boolean isEmpty() {
        return top == -1;
    }

    public boolean isFull() {
        return top == maxSize - 1;
    }
}
